/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  							 script_has_artifact.cpp

	$Header: /heroes4/script_has_artifact.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "script_has_artifact.h"

#include "army.h"
#include "army_array.h"
#include "artifact.h"
#include "artifact_slot.h"
#include "default_artifacts.h"
#include "enum_operations.h"
#include "hero.h"
#include "player.h"
#include "read_script_target_from_map.h"
#include "script_targeting.h"
#include "sized_int_types.h"
#include "streambuf_operators.h"
#include "town.h"

// --------------------------------------------------------------------------
// t_script_has_artifact members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_script_has_artifact::t_result
t_script_has_artifact::evaluate(t_expression_context_hero const& context) const
{
	if (m_target_is_player) {
		t_player const* player = select_player_by_target(m_target.player, context.map, NULL, context.army_owner, context.opposing_army_owner);
		return do_evaluate(player);
	} else {
		if (m_target.stack == k_script_stack_target_this) 
			return do_evaluate(context.hero);
		else {
			t_creature_array const* target = select_creature_array_by_target(m_target.stack, NULL, context.army, context.opposing_army);
			return do_evaluate(target);
		}
	}
}

t_script_has_artifact::t_result
t_script_has_artifact::evaluate(t_expression_context_town const& context) const
{
	if (m_target_is_player) {
		t_player const* player = select_player_by_target(m_target.player, context.map, context.object, context.garrison ? context.garrison->get_owner() : NULL, context.opposing_army_owner);
		return do_evaluate(player);
	} else {
		t_creature_array const* target = select_creature_array_by_target(m_target.stack, context.garrison, NULL, context.opposing_army);
		return do_evaluate(target);
	}
}

t_script_has_artifact::t_result
t_script_has_artifact::evaluate(t_expression_context_object const& context) const
{
	if (m_target_is_player) {
		t_player const* player = select_player_by_target(m_target.player, context.map, NULL, NULL, NULL);
		return do_evaluate(player);
	} else {
		assert(false);
		return false;
	}
}

t_script_has_artifact::t_result
t_script_has_artifact::evaluate(t_expression_context_army const& context) const
{
	if (m_target_is_player) {
		t_player const* player = select_player_by_target(m_target.player, context.map, NULL, context.army_owner, context.opposing_army_owner);
		return do_evaluate(player);
	} else {
		t_creature_array const* target = select_creature_array_by_target(m_target.stack, NULL, context.army, context.opposing_army);
		return do_evaluate(target);
	}
}

t_script_has_artifact::t_result
t_script_has_artifact::evaluate(t_expression_context_global const& context) const
{
	if (m_target_is_player) {
		t_player const* player = select_player_by_target(m_target.player, context.map, NULL, NULL, NULL);
		return do_evaluate(player);
	} else {
		assert(false);
		return false;
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_script_has_artifact::t_result	
t_script_has_artifact::do_evaluate(t_creature_stack const* stack) const
{
	if (stack == NULL) return false;

	for (int i = 0; i < stack->get_backpack_count(); i++) 
		if (stack->get_backpack_slot(i).get_icon() == m_artifact.get_icon()) 
			return true;

	for (t_artifact_slot slot = t_artifact_slot(0); slot < k_artifact_slot_hero_count; enum_incr( slot ))
	{
		t_artifact const& artifact = stack->get_artifact(slot);
		if (artifact.get_icon() == m_artifact.get_icon())
			return true;
	}

	return false;
}

t_script_has_artifact::t_result	
t_script_has_artifact::do_evaluate(t_creature_array const* array) const
{
	if (array == NULL) return false;

	for (int i = 0; i < t_creature_array::k_size; i++) {
		t_creature_stack const& stack = (*array)[i];
		if (do_evaluate(&stack)) 
			return true;
	}
	
	return false;
}

t_script_has_artifact::t_result	
t_script_has_artifact::do_evaluate(t_player const* player) const
{
	if (!player) return false;

	t_army_array const* armies = player->get_armies();
	if (!armies) return false;

	int count = armies->size();

	for (int i = 0; i < count; i++) 
	{
		t_army_ptr army = (*armies)[i];
		if (army.get() == NULL) continue;

		if (do_evaluate(&army->get_creatures()))
			return true;
	}

	return false;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_script_has_artifact::read( std::streambuf & stream, int version )
{
	if (!t_abstract_script_boolean_expression::read( stream, version ))
		return false;

	m_target_is_player = get< bool >( stream );

	if ( m_target_is_player )
		m_target.player = get< t_player_target >( stream );
	else
		m_target.stack = get< t_stack_target >( stream );

	return m_artifact.read( stream );
}



// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_script_has_artifact::read_from_map(
	std::streambuf &	stream,
	int					format_version )
{
	m_target_is_player = get< t_uint8 >( stream ) != 0;

	bool read_result;
	if ( m_target_is_player )
		read_result = read_script_target_from_map( stream, format_version, m_target.player );
	else
		read_result = read_script_target_from_map( stream, format_version, m_target.stack );
	if ( !read_result )
		return false;

	return ::read_from_map( stream, m_artifact );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_script_has_artifact::write( std::streambuf & stream ) const
{
	if (!t_abstract_script_boolean_expression::write( stream ))
		return false;

	put< bool >( stream, m_target_is_player );

	if ( m_target_is_player )
		put< t_player_target >( stream, m_target.player );
	else
		put< t_stack_target >( stream, m_target.stack );

	return m_artifact.write( stream );
}

